home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’92 / The Essential Hack / Essential.a next >
Encoding:
Text File  |  1992-06-18  |  24.0 KB  |  890 lines  |  [TEXT/MPS ]

  1. ;    The Essence-Shell Hack
  2.  
  3. ; To Do:
  4. ;    _ use a resource or table to specify which traps and vectors to patch,
  5. ;        and have a small routine to do all the patching.
  6.  
  7. ; Allan and Scott wrote this one day in June, not long before MacHack ’92
  8.  
  9. ;        arf        6/16/92        Fixed up the menuHook stuff.  Patching InitMenus was bogus
  10. ;                            because we were only storing one old MenuHook value, but each
  11. ;                            app gets its own copy, and we’d have to maintain one per
  12. ;                            process.  That would be lame.  Now we’ll hook in right
  13. ;                            as the user clicks in the menu bar, then unhook when they’re done.
  14. ;        stb        6/16/92        Showed this to a bunch of guys who had next to nothing
  15. ;                            to say.  Gee, thanks, guys :-)  Normalized spelling,
  16. ;                            and added more comments.
  17. ;        stb        6/16/92        Whoops, InitMenus clears MenuHook.  Time to tail-patch InitMenus!
  18. ;        stb        6/16/92        Hook into MenuHook.
  19. ;        stb        6/16/92        Merge in Allan’s Gestalt code.  It’s hard to get used
  20. ;                            to this three hour time difference!
  21. ;        stb        6/15/92        Add alternate icon drawing; try drawing all the way
  22. ;                            across the menu bar instead of a simple rect at the left.
  23. ;                            Hmm, it fits better, but it’s harder to see it all at once.
  24. ;        stb        6/14/92        Change some names for clarity
  25.  
  26. ;Include only the minimum necessary!
  27.  
  28.         CASE    OBJECT
  29.         STRING    ASIS
  30.         
  31.         PRINT    PUSH
  32.         PRINT    OFF
  33.  
  34.         INCLUDE    'Traps.a'
  35. wholeQuick    EQU    1
  36.         INCLUDE    'QuickEqu.a'
  37. wholeSystem    EQU 1
  38.         INCLUDE    'SysEqu.a'
  39. ;wholeTools    EQU    0
  40. ;        INCLUDE    'ToolEqu.a'
  41. ;        INCLUDE    'PackMacs.a'
  42. ;        INCLUDE    'Types.a'
  43.  
  44.         PRINT    POP
  45.  
  46.         SEG        'Essential'
  47.         PROC
  48. StartOfCode
  49. ;        _Debugger            ; it’s good to make it easy to trace while developing…
  50.         Bra        Essential
  51.         DC.B    'Allan & Scott wrote this one day shortly before MacHack ’92'
  52.         
  53.         Align    2
  54.  
  55. WayBadValue    equ    $50FF8001    ; borrowed this value from EvenBetterBusError
  56.                             ; just in case we do something wrong, we’ll
  57.                             ; know right away.
  58.  
  59. ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  60. HeapBlock    ;This block contains the patches.
  61. MenuHook        equ    $A30
  62.  
  63. PatchMenuSelect
  64. ; Stuff MenuHook with our jump table entry to our drawing proc.
  65. ; We do this because InitMenus clears out MenuHook.
  66.  
  67.         LEA        MenuHook,A0                ; Strange, if I hadn’t declared MenuHook, Asm
  68.                                         ;    thought it should be *+99E!
  69.         Lea        OldMenuHook,A1
  70.         move.L    (A0),(A1)                ; Save the old one...
  71.         Move.L    pMenuHookEA,(A0)        ; stuff our proc in, and just assume, for now,
  72.         Move.L    OldMenuSelect,A0
  73.         Clr.L    -(SP)                    ; room for the new result
  74.         Move.L    8(SP),-(SP)                ; copy the mouse pt
  75.         JSR        (A0)                    ; Call the old one
  76.         Move.L    (SP)+,8(SP)                ; put the result back for the caller
  77.         Move.l    (SP)+,(SP)                ; Push the return address
  78.         LEA        MenuHook,A0
  79.         Move.L    oldMenuHook,(A0)        ; stuff our proc in, and just assume, for now,
  80.                                         ; that no one else is patching it.
  81.         RTS
  82. OldMenuSelect    DC.L    WayBadValue
  83. pMenuHookEA        DC.L    WayBadValue        ; <ea> of pMenuHook+4.  Can’t get to it via
  84.                                         ; other means because it’s in a separate block.
  85.  
  86. PatchNewHandle
  87. ; Count each time through.
  88.         Move.L    A0,-(sp)
  89.         LEA        NewHandleCounter,A0
  90.         Add.L    #1,(a0)
  91.         Move.L    (SP)+,A0
  92.         Move.L    OldNewHandle,-(sp)
  93.         RTS
  94. OldNewHandle    DC.L    WayBadValue
  95.  
  96. PatchDisposeHandle
  97. ; Count each time through.
  98.         Move.L    A0,-(sp)
  99.         LEA        DisposeHandleCounter,A0
  100.         Add.L    #1,(a0)
  101.         Move.L    (SP)+,A0
  102.         Move.L    OldDisposeHandle,-(sp)
  103.         RTS
  104. OldDisposeHandle    DC.L    WayBadValue
  105.  
  106.  
  107. PatchNewPtr
  108. ; Count each time through.
  109.         Move.L    A0,-(sp)
  110.         LEA        NewPtrCounter,A0
  111.         Add.L    #1,(a0)
  112.         Move.L    (SP)+,A0
  113.         Move.L    OldNewPtr,-(sp)
  114.         RTS
  115. OldNewPtr    DC.L    WayBadValue
  116.  
  117.  
  118. PatchDisposePtr
  119. ; Count each time through.
  120.         Move.L    A0,-(sp)
  121.         LEA        DisposePtrCounter,A0
  122.         Add.L    #1,(a0)
  123.         Move.L    (SP)+,A0
  124.         Move.L    OldDisposePtr,-(sp)
  125.         RTS
  126. OldDisposePtr    DC.L    WayBadValue
  127.  
  128. PatchRead
  129. ; Don’t count Read’s, but instead decide whether GetResource or LoadSeg
  130. ; hit the disk, and count for them.
  131.         Move.L    A0,-(sp)
  132.         LEA        ReadCounter,A0
  133.         Add.L    #1,(a0)
  134.         Move.W    inLoadSeg,D0        ; can you see why this is not really giving
  135.                                     ; us what we’d really like to get?
  136.         Beq.S    @1
  137.         LEA        LoadSegHitDisk,A0
  138.         Add.L    #1,(A0)
  139. @1        Move.W    inGetResource,D0    ; this lets us see that the GetResource actually
  140.                                     ; hit the disk, so it cost us something.
  141.         Beq.S    @2
  142.         LEA        GetResourceHitDisk,A0
  143.         Add.L    #1,(A0)
  144. @2        Move.L    (SP)+,A0
  145.         Move.L    OldRead,-(sp)
  146.         RTS
  147. OldRead        DC.L    WayBadValue
  148.  
  149. PatchWrite
  150. ; Count each time through.
  151.         Move.L    A0,-(sp)
  152.         LEA        WriteCounter,A0
  153.         Add.L    #1,(a0)
  154.         Move.L    (SP)+,A0
  155.         Move.L    OldWrite,-(sp)
  156.         RTS
  157. OldWrite    DC.L    WayBadValue
  158.  
  159. PatchLoadSeg
  160. ; Count each time through.
  161. ; You just can’t tail-patch this trap, nor can you change any registers.
  162.         Move.L    A0,-(sp)
  163.         LEA        LoadSegCounter,A0
  164.         Add.L    #1,(a0)
  165.         LEA        inLoadSeg,A0
  166.         Move.W    #1,(A0)
  167.         Move.L    (SP)+,A0
  168.         Move.L    OldLoadSeg,-(sp)
  169.         RTS
  170. OldLoadSeg    DC.L    WayBadValue
  171.  
  172. GetResourceFrame    RECORD    {Link},Decr
  173. Result        DS.L    1                        ; Stack frome for GetResource
  174. Type        DS.L    1
  175. ID            DS.W    1                            
  176. Return        DS.L    1
  177. Link        DS.L    1
  178. FrameSize    EQU        *-GetResourceFrame
  179.             ENDR
  180.  
  181. PatchGetResource
  182. ; Count each time through, and set a flag so we can tell if we hit the disk,
  183. ; and count those, too.
  184.         With    GetResourceFrame
  185.         Link    A6,#FrameSize
  186.         Move.L    A0,-(sp)                        ; save A0
  187.         LEA        GetResourceCounter,A0
  188.         Add.L    #1,(a0)
  189.         LEA        inGetResource,A0
  190.         Move.W    #1,(A0)
  191.         Move.L    (SP)+,A0                        ; restore A0
  192.  
  193.         Move.L    Result(a6),-(sp)                ; Move the result value...
  194.         Move.L    Type(a6),-(sp)                    ; and the type
  195.         Move.W    ID(a6),-(sp)                    ; and the ID
  196.         
  197.         Pea        MyTailPatch                        ; The place for us to return to
  198.         Move.L    OldGetResource,-(sp)
  199.         RTS                                        ; Do Scott’s Really cool Jump with No registers Blown
  200.         
  201. MyTailPatch
  202.         Move.L    A0,-(SP)
  203.         
  204.         LEA        inGetResource,A0
  205.         Clr.W    (A0)                            ; OK, So now we are back, and we can clean up
  206.         LEA        inLoadSeg,A0
  207.         Clr.W    (A0)
  208.         
  209.         Move.L    (SP)+,A0
  210.         
  211.         Move.L    (SP)+,Result(a6)
  212.         Unlk    A6
  213.         Move.L    (SP),6(SP)                        ; Put the return address up the stack,
  214.         Add        #6,SP                            ; and clean up the stack
  215.         RTS
  216.         
  217.         EndWith 
  218.         
  219. OldGetResource
  220.         DC.L    WayBadValue
  221.  
  222.  
  223. redrawInterval    equ    60
  224.  
  225. PatchMenuHook
  226.     ; for now, just drop on through.  As it currently stands, this
  227.     ; slows down menu selection a lot, but it looks cool.
  228.         MoveM.L    D0-D2/A0-A1,-(SP)
  229.         BSR.S    DoTheDrawing
  230.         LEA        OldMenuHook,A0
  231.         Move.L    OldMenuHook,D0
  232.         BEq.S    @Done                        ; is it NIL?
  233.         CMP.L    #-1,D0                        ; is it F’s?
  234. @Done    MoveM.L    (SP)+,D0-D2/A0-A1            ; cool, this doesn’t whack the CCs.
  235.         BEq.S    @WowNobodyElseIsOnMenuHook    ; jumping to 0 is usually a bad idea
  236.         Move.L    OldMenuHook,-(sp)
  237. @WowNobodyElseIsOnMenuHook
  238.         RTS
  239.  
  240. OldMenuHook
  241.         DC.L    WayBadValue
  242.  
  243.  
  244. PatchGNEFilter
  245.  
  246.         MoveM.L    D0-D2/A0-A1,-(SP)
  247.  
  248.         Move.L    evtTicks(A1),D1                ; tickCount as of now
  249.         Move.L    GNEFilterTimer,D2            ; tickCount at last update
  250.         sub.L    D2,D1                        ; ticks since last update
  251.         cmp.L    #redrawInterval,D1
  252. ;        blt.S    @Done                        ; branch if elapsed < redrawInterval
  253.         LEA        GNEFilterTimer,A0
  254.         Move.L    evtTicks(a1),(a0)            ; remember the time
  255.  
  256. ;        Clr.W    -(SP)
  257. ;        _FlashMenuBar
  258. ;        LEA        DebugFlag,A0
  259. ;        Tst.W    (A0)
  260. ;        Bne.S    @Done
  261. ;        _Debugger
  262.         
  263.         BSR.S    DoTheDrawing
  264.         BSR        ClearTheDataBlock
  265.  
  266.         LEA        OldGNEFilter,A0
  267.         Tst.L    (A0)
  268. @Done    MoveM.L    (SP)+,D0-D2/A0-A1            ; cool, this doesn’t whack the CCs.
  269.         BEq.S    @WowNobodyElseIsOnGNEFilter    ; jumping to 0 is usually a bad idea
  270.         Move.L    OldGNEFilter,-(sp)
  271. @WowNobodyElseIsOnGNEFilter
  272.         RTS
  273.  
  274. OldGNEFilter
  275.         DC.L    WayBadValue
  276. GNEFilterTimer
  277.         DC.L    0
  278.  
  279.  
  280.  
  281. DoTheDrawing
  282. ; save the port
  283. ; set the port to the WindowMgr port
  284. ; draw something
  285.  
  286. WMgrPort        equ    $9DE
  287.  
  288. ; save our registers
  289. ; d4    thePort
  290. ; d5    windowPtr
  291.             MoveM.L    a0-a2/d4-d5,-(sp)
  292.  
  293. ;    save thePort
  294.             Movea.L    (a5),a0                ; get address of thePort
  295.             Move.L    (a0),d4                ; save it
  296. ;    set thePort to the WMgrPort
  297.             Movea.L    WMgrPort,a2
  298.             Move.L    a2,-(A7)            ; keep it handy
  299.             _SetPort
  300.  
  301. ;    Save the clip
  302.             Clr.L    -(SP)                ; save it on the stack for later
  303.             _NewRgn
  304.  
  305.             Move.L    (sp),-(sp)            ; spare copy of the handle for SetClip
  306.             Move.L    (sp),-(sp)            ; spare copy of the handle for DisposeRgn
  307.             _GetClip                    ; this consumes the first copy of the
  308.                                         ;    handle, but the second copy points
  309.                                         ;    to the same thing, and we’ll leave it
  310.                                         ;    there for a while.
  311.  
  312. ;    set the clip to the whole screen
  313.             Pea        portBits+bounds(a2)    ; the rectangle of the window mgr port
  314.             _ClipRect
  315.  
  316. ;    OffsetRect( copy of the bitmap rect, right(thePort^.portRect), bottom(thePort^.portRect) )
  317. ;    Set up the target rectangle to be where the grow icon is            
  318. ;            LEA        pTargetRect,a1        ; point to the target rectangle
  319. ;            Move.L    a1,-(sp)            ; push target rectangle address
  320.  
  321. ;            LEA        bounds+pBitmap,a0    ; point to the rect in the bitmap
  322. ;            Move.L    (a0)+,(a1)+            ; copy first part of rect into target rectangle
  323. ;            Move.L    (a0)+,(a1)+            ; copy second part
  324.  
  325. ;            Move.L    a2,a0                            ; a0 <- thePort
  326. ;            Move.L    portRect+botRight(a0),-(sp)        ; botRight(thePort)
  327.  
  328. ;            Move.L    (sp),d0                ; offset the size of the grow icon
  329. ;            sub.W    #$0D,d0
  330. ;            swap    d0
  331. ;            sub.W    #$0E,d0
  332. ;            swap    d0
  333. ;            Move.L    d0,(sp)
  334. ;            _OffsetRect
  335.  
  336. ; this is where we draw the icon
  337. ;    CopyBits (srcBits,dstBits: BitMap; srcRect,dstRect: Rect; mode: INTEGER; maskRgn: RgnHandle)
  338.  
  339. ShiftMask    equ    0
  340.  
  341.             LEA        KeyMap,a0
  342.             BTST     #ShiftMask,7(a0)
  343.             BEQ.S    @NormalDrawing
  344.             
  345.             LEA        pAlternateBitMap,a0
  346.             Move.L    a0,-(sp)            ; push the icon
  347.             LEA        pIcon,a1
  348.             Move.L    a1,(a0)
  349.  
  350.             Movea.L    WMgrPort,a0
  351.             LEA        portBits(a0),a0        ; push dstBits, thePort^.portBits
  352.             Move.L    a0,-(sp)
  353.  
  354.             LEA        bounds+pAlternateBitMap,a0    ; point to the rect in the bitmap
  355.             Move.L    a0,-(sp)            ; source rect is from the bitmap
  356.             Bra.S    @AbnormalDrawing
  357.  
  358. @NormalDrawing
  359.             LEA        pBitmap,a0            ; push the counters as srcBits
  360.             Move.L    a0,-(sp)
  361.  
  362.             Movea.L    WMgrPort,a0
  363.             LEA        portBits(a0),a0        ; push dstBits, thePort^.portBits
  364.             Move.L    a0,-(sp)
  365.  
  366.             LEA        bounds+pBitmap,a0    ; point to the rect in the bitmap
  367.             Move.L    a0,-(sp)            ; source rect is from the bitmap
  368.  
  369. @AbnormalDrawing
  370. ;            LEA        pTargetRect,a0        ;
  371.             Move.L    a0,-(sp)            ; dest rect is bottom-right of the window
  372.             
  373.             Move.W    #srcCopy,-(sp)        ; push mode = srcCopy=0
  374.             Move.L    #0,-(sp)            ; push maskRgn = NIL
  375.             _CopyBits
  376.  
  377.             _SetClip                    ; restore the clip with the rgn we saved
  378.                                         ;    on the stack earlier
  379.             _DisposeRgn                    ; dispose the rgn.  Good thing we saved
  380.                                         ;     a copy on the stack, huh?
  381.                                         ;    Made a really common mistake earlier
  382.                                         ;    by forgetting to make this call.  Didn’t
  383.                                         ;    find out until I left the machine running
  384.                                         ;    long enough to run a heap completely out
  385.                                         ;    of memory.
  386. ; ••• maybe we should set the heap to something like SysZone so we don’t
  387. ; ••• screw up apps with finely-tuned heaps (like the Finder).
  388. ; ••• This is being way too cavalier, but we don’t have any time left!  Argh!
  389.  
  390. Bail
  391.             Move.L    d4,-(sp)            ; put the saved thePort back the way it was
  392.             _SetPort
  393.  
  394. @done
  395.             MoveM.L    (sp)+,a0-a2/d4-d5    ; put the registers back
  396. quickExit
  397.             RTS
  398.  
  399. ; restore the port
  400.         Align    2
  401.  
  402.  
  403. ;     This is the routine called by Gestalt to return the Proc Pointer.
  404. ;
  405. ;    OSErr gestaltSelectorProc(OSType selector,long *response);
  406. ;
  407. ;    Since this is called from Gestalt, we do not have to save any registers
  408.  
  409. ReturnTheGestaltHandlerProc
  410.         
  411.         LEA        GestaltHandlerProc,A1
  412.         Move.W    #0,$0a(Sp)                        ; No Error occurred here!
  413.         Move.L    4(SP),A0
  414.         Move.L    A1,(A0)                            ; put the result into the right place....
  415.         Move.L    (SP)+,A0                        ; Get the return address
  416.         Addq.W    #8,A7                            ; Lost the args
  417.         Jmp        (A0)                            ; And return
  418.         
  419. ReturnDataBlock
  420.         LEA        NewHandleCounter,A1
  421.         RTS
  422.  
  423. ;
  424. ;        This Function clears the counters, and updates the running totals...
  425. ;
  426.  
  427. ClearTheDataBlock
  428.         LEA        NewHandleCounter,A0
  429.         Move.L    (A0),D0
  430.         Add.L    D0,4(A0)
  431.         Clr.L    (A0)
  432.         LEA        DisposeHandleCounter,A0
  433.         Move.L    (A0),D0
  434.         Add.L    D0,4(A0)
  435.         Clr.L    (A0)
  436.         LEA        NewPtrCounter,A0
  437.         Move.L    (A0),D0
  438.         Add.L    D0,4(A0)
  439.         Clr.L    (A0)
  440.         LEA        DisposePtrCounter,A0
  441.         Move.L    (A0),D0
  442.         Add.L    D0,4(A0)
  443.         Clr.L    (A0)
  444.         LEA        ReadCounter    ,A0
  445.         Move.L    (A0),D0
  446.         Add.L    D0,4(A0)
  447.         Clr.L    (A0)
  448.         LEA        WriteCounter,A0
  449.         Move.L    (A0),D0
  450.         Add.L    D0,4(A0)
  451.         Clr.L    (A0)
  452.         LEA        LoadSegCounter,A0
  453.         Move.L    (A0),D0
  454.         Add.L    D0,4(A0)
  455.         Clr.L    (A0)
  456.         LEA        LoadSegHitDisk,A0
  457.         Move.L    (A0),D0
  458.         Add.L    D0,4(A0)
  459.         Clr.L    (A0)
  460.         LEA        GetResourceCounter,A0
  461.         Move.L    (A0),D0
  462.         Add.L    D0,4(A0)
  463.         Clr.L    (A0)
  464.         LEA        GetResourceHitDisk,A0
  465.         Move.L    (A0),D0
  466.         Add.L    D0,4(A0)
  467.         Clr.L    (A0)
  468.         Move.L    #0,A1
  469.  
  470.         RTS
  471.         
  472.         
  473.         
  474. ;    Define a routine actually does the gestalt things....
  475. ;    Has the following interface.
  476. ;
  477. ;    Defined using Pascal syntax, since we may want to call it from there!
  478. ;
  479. ;    long GestaltHandlerProc(short selector, char *param);
  480. ;
  481.  
  482. sTablePointer    equ        0
  483. sClearTable        equ        1
  484. sUninstall        equ        2
  485.  
  486.  
  487. GestaltHandlerFrame    RECORD    {Link},Decr
  488. Result        DS.L    1                        ; Stack frome for GestaltHandlerProc
  489. selector    DS.W    1
  490. param        DS.L    1                            
  491. Return        DS.L    1
  492. Link        DS.L    1
  493. FrameSize    EQU        *-Link
  494.             ENDR
  495.  
  496. GestaltHandlerProc
  497.         With        GestaltHandlerFrame
  498.         Link        A6,#FrameSize                ; No need for locals here
  499.         MoveM.L        A0-A2/D0-D2,-(SP)            ; save some registers
  500.         Move.W        selector(A6),D0
  501.         Move.L        param(A6),A1
  502.         ASL.W        #2,D0                        ; multiply by 4
  503.         LEA            myJumpTable,A0
  504.         Move.W        (A0,D0.W),D0                ; index to find the right code...
  505.         JSR            (A0,D0.W)                    ; and do the thing....
  506.         Move.L        A1,Result(A6)                ; and put the result back
  507.         Unlk        A6
  508.         MoveM.L        (SP)+,A0-A2/D0-D2            ; restore the registers
  509.         Move.L        (SP),$6(A6)                    ; Move the return address up....
  510.         Addq        #6,SP                        ; clean up the stack
  511.         RTS
  512.         EndWith
  513.  
  514. ;    Set up our jumptable.
  515. ;    All these values should be negative, since they are before this!
  516. ;
  517.  
  518. myJumpTable    
  519.  
  520.         DC.W        ReturnDataBlock - myJumpTable
  521.         DC.W        ClearTheDataBlock - myJumpTable
  522.         DC.W        RemovePatches - myJumpTable
  523.         DC.W        0
  524.  
  525.  
  526.  
  527.         Align    2
  528.         
  529.  
  530. ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  531.  
  532. GeneralStorage
  533.  
  534. PatchPtr                DC.L    0    ; to keep a ptr to the patch table
  535. DebugFlag                DC.W    1    ; swapped this and PatchPtr to keep .W’s together.  Seems neater.
  536. didARead                DC.W    0
  537. inGetResource            DC.W    0
  538. inLoadSeg                DC.W    0
  539.  
  540. pAlternateBitMap
  541.             DC.L    WayBadValue        ; baseaddress will point to pIcon
  542.             DC.W    80                ; rowBytes = 2
  543.                                     ; rect is top,left,bottom,right
  544.             DC.W    $0,$0,1,640    ; rect = (0,0)(32 bits,10 values + 9 pad values)
  545. pIcon        DC.L    $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
  546.             DC.L    0
  547.  
  548.  
  549. pRectangle    DS.W    4                ; a rect needs four words
  550. pTargetRect    DS.W    4
  551.  
  552. pBitmap
  553.             DC.L    WayBadValue        ; baseaddress will point to pIcon
  554.             DC.W    80                ; rowBytes = 20Longs * 4bytes/Long
  555.                                     ; rect is top,left,bottom,right
  556.             DC.W    $0,$0,1,640    ; rect = (0,0)(32 bits,10 values + 9 pad values)
  557. pBitMapBaseAddress
  558. ;        The table is kept as two longs,  The first is the count,
  559. ;        which is reset every time, and the second is a running total, Never reset.
  560.  
  561. NewHandleCounter        DC.L    0,0
  562. DisposeHandleCounter    DC.L    0,0
  563. NewPtrCounter            DC.L    0,0
  564. DisposePtrCounter        DC.L    0,0
  565. ReadCounter                DC.L    0,0
  566. WriteCounter            DC.L    0,0
  567. LoadSegCounter            DC.L    0,0
  568. LoadSegHitDisk            DC.L    0,0
  569. GetResourceCounter        DC.L    0,0
  570. GetResourceHitDisk        DC.L    0,0
  571.  
  572. EndOfTheList            DC.L    -1,-1,-1,-1
  573.  
  574.  
  575. ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  576. RemovePatches
  577. ;    This routine goes in and removes the patches installed.
  578. ;    then disposes of itself.... REMARKABLE!!!
  579.  
  580.     ; First set up the real patches
  581.     
  582.         Move.L    PatchPtr,a0
  583.  
  584.         Move.L    OldNewHandle,A1
  585.         Move.L    a1,pNewHandle-JumpTable(A0)
  586.  
  587.         Move.L    OldMenuSelect,A1
  588.         Move.L    a1,pMenuSelect-JumpTable(A0)
  589.  
  590.         Move.L    OldDisposeHandle,A1
  591.         Move.L    a1,pDisposeHandle-JumpTable(A0)
  592.  
  593.         Move.L    OldNewPtr,A1
  594.         Move.L    a1,pNewPtr-JumpTable(A0)
  595.  
  596.         Move.L    OldDisposePtr,A1
  597.         Move.L    a1,pDisposePtr-JumpTable(A0)
  598.  
  599.         Move.L    OldRead,A1
  600.         Move.L    a1,pRead-JumpTable(A0)
  601.  
  602.         Move.L    OldWrite,A1
  603.         Move.L    a1,pWrite-JumpTable(A0)
  604.         
  605.         Move.L    OldLoadSeg,A1
  606.         Move.L    a1,pLoadSeg-JumpTable(A0)
  607.  
  608.         Move.L    OldGetResource,A1
  609.         Move.L    a1,pGetResource-JumpTable(A0)
  610.  
  611.         Move.L    OldGNEFilter,A1
  612.         Move.L    a1,pGNEFilter-JumpTable(A0)
  613.  
  614.         LEA        pDummyGestalt-JumpTable(A0),A1
  615.         Move.L    A1,pGestaltFunc-JumpTable(A0)
  616.  
  617.         LEA    HeapBlock,a0
  618.         _DisposPtr
  619.         RTS
  620.  
  621.  
  622. HeapBlockEnd
  623.  
  624. ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  625.  
  626. JumpTable
  627. ; This block contains the jumps so we can dispose of the real patches
  628. ; later if we want to.
  629.  
  630. ; remember to build a MacsBug template to display this stuff with names.
  631.  
  632. ; Ok, this has grown to the point where it should really be table-driven,
  633. ; but it’s getting close to time for the talk…
  634.  
  635.         DC.B    'MaChAcK'
  636.         ALIGN    4
  637.  
  638.     MACRO
  639.     OurStandardJumpTableEntry
  640.         DC.L    WayBadValue
  641.         Move.L    *-4,-(sp)
  642.         RTS
  643.     ENDM
  644.  
  645.  
  646. pGNEFilter        OurStandardJumpTableEntry
  647. pMenuHook        OurStandardJumpTableEntry
  648. pMenuSelect        OurStandardJumpTableEntry
  649. pNewHandle        OurStandardJumpTableEntry
  650. pDisposeHandle    OurStandardJumpTableEntry
  651. pNewPtr            OurStandardJumpTableEntry
  652. pDisposePtr        OurStandardJumpTableEntry
  653. pRead            OurStandardJumpTableEntry
  654. pWrite            OurStandardJumpTableEntry
  655. pLoadSeg        OurStandardJumpTableEntry
  656. pGetResource    OurStandardJumpTableEntry
  657. pGestaltFunc    OurStandardJumpTableEntry
  658.         
  659. ;    We define this, so that when we uninstall, we can handle a gestalt call....
  660. ;    And just return an error
  661. ;    This is because Gestalt does not allow us to UNINSTALL a handler....
  662. ;    hmmm.... BOGUS!
  663.  
  664. pDummyGestalt
  665.         Move.W    #-5551,$C(Sp)                    ; Selector Not defined!
  666.         Move.L    (SP),8(SP)                        ; Get the return address
  667.         Addq.W    #8,A7                            ; Lose the args
  668.         RTS                                        ; And return
  669.  
  670. JumpTableEnd
  671. ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  672.  
  673. Credits
  674.         DC.B    'AppleLink addresses:  Allan & Scott'
  675.         
  676.         ALIGN     2
  677.  
  678. Essential
  679.  
  680. ;Set up here.
  681.  
  682. ; Typically, you should mark your INIT resource as Preload & Locked.
  683. ; This gets it in the "application" heap nice and early and nice and low.
  684. ; Because we are going to do that, we’re not going to waste code to
  685. ; do what the resource manager is happy to do for us.
  686.  
  687. ;        lea    StartOfCode,a0
  688. ;        _RecoverHandle
  689. ;        _HLock            ; just lock me down in case...
  690.  
  691. ; Do the polite thing, and don’t load if the user doesn’t want us.
  692.         LEA        KeyMap,a0
  693.         BTST     #ShiftMask,7(a0)
  694.         BNZ        BailOut
  695.  
  696. NewHandle        equ    $A122
  697. MenuSelect        equ    $A93D
  698. DisposeHandle    equ    $A023
  699. NewPtr            equ    $A11E
  700. DisposePtr        equ    $A01F
  701. Read            equ    $A002
  702. Write            equ    $A003
  703. LoadSeg            equ $A9F0
  704. GetResource        equ    $A9A0
  705.  
  706. ;    jGNEFilter        equ 666                ; You decide…
  707.  
  708. ; Set up the patches-to-be.  We get the old trap or vector address.
  709. ; We then stuff that address into a piece of storage right after the
  710. ; patch code which uses it.  Note that this is making the change to 
  711. ; the INIT resource.  Down below we create the patch block and move
  712. ; the patch code and the embedded addresses we store here into a new
  713. ; block in the system heap.
  714.  
  715. GetAndRememberOldTrapAddresses
  716.  
  717.         LEA        OldGNEFilter,A0
  718.         Move.L    jGNEFilter,(A0)        ; save off the old jGNEFilter
  719.  
  720.     MACRO
  721.     SaveOldTrapAddress &trapNumber, &trapType, &storage
  722.         Move.W    #&trapNumber,D0
  723.         _GetTrapAddress &trapType
  724.         LEA    &storage,A1
  725.         Move.L    A0,(A1)
  726.     ENDM
  727.  
  728.         SaveOldTrapAddress    MenuSelect,        newTool,    OldMenuSelect
  729.         SaveOldTrapAddress    NewHandle,        newOS,        OldNewHandle
  730.         SaveOldTrapAddress    DisposeHandle,    newOS,        OldDisposeHandle
  731.         SaveOldTrapAddress    NewPtr,            newOS,        OldNewPtr
  732.         SaveOldTrapAddress    DisposePtr,        newOS,        OldDisposePtr
  733.         SaveOldTrapAddress    Read,             newOS,        OldRead
  734.         SaveOldTrapAddress    Write,            newOS,        OldWrite
  735.         SaveOldTrapAddress    LoadSeg,        newTool,    OldLoadSeg
  736.         SaveOldTrapAddress    GetResource,    newTool,    OldGetResource
  737.  
  738. ; Put the patch jump table into a system heap block, henceforth called JumpTable
  739.  
  740. CreateJumpTableBlock
  741.         Move.L    #JumpTableEnd-JumpTable,D1
  742.         Move.L    D1,D0
  743.         _NewPtr sys
  744.         Move.L    A0,A1            ; the new pointer block is the destination
  745.         LEA        JumpTable,A0    ; the jump table is what we’re copying
  746.         Move.L    D1,D0
  747.         _BlockMove                ; copy the jump table
  748.         LEA        PatchPtr,A0
  749.         Move.L    a1,(A0)            ; remember where we left the jump table
  750.         
  751. ; Put the patch code into a system heap block, henceforth called HeapBlock
  752.  
  753. CreatePatchBlock
  754.         Move.L    #HeapBlockEnd-HeapBlock,D1
  755.         Move.L    D1,D0
  756.         _NewPtr sys
  757.         Move.L    A0,A1            ; the new pointer block is the destination
  758.         LEA    HeapBlock,A0        ; HeapBlock is the source
  759.         Move.L    D1,D0            ; D1 is how many bytes are in our patch
  760.         _BlockMove                ; copy all of the patch code into the new block
  761.         Move.L    A1,A2            ; Save the new pointer block in A2
  762.  
  763. InstallPatches
  764.  
  765.          Move.L    PatchPtr,a1
  766.  
  767. FlushTheCache
  768.         _FlushInstructionCache    ; just flush all the caches.  We just moved code
  769.                                 ; into a couple of blocks which might still have addresses 
  770.                                 ; in the instruction cache.  Currently BlockMove does
  771.                                 ; this, but why count on it when it only costs 4 bytes?
  772.  
  773. ; Detailed description of how we hook in:
  774. ;    1. Figure out the address of the patch routine in the new block of patches.
  775. ;    2. Stuff the patch routine’s address into the new jump table block.
  776. ;    3. Figure out the address of the “Move.L *-4,-(sp)” which is right after
  777. ;        the address we just stored in the jump table.
  778. ;    4. Hook that address in.  Either stuff it into the right vector, or set
  779. ;        the trap address, as appropriate.
  780. ;
  781. ; The blow-by-blow:
  782. ;
  783. ; 1. Point A0 at the patch block (at A2) plus the offset to the patch routine.
  784. ;     A0 := A2 + (<ea> of patch routine - <ea> of the start of the patches)
  785. ;        LEA        PatchGNEFilter-HeapBlock(A2),A0
  786. ;
  787. ; 2. Stuff that address into the newly-allocated jump table (at A1) plus the offset
  788. ;     to the jump table entry.
  789. ;     Ptr( A1 + (<ea> of the jump table entry - <ea> of the start of the jump table) := A0
  790. ;        Move.L    A0,pGNEFilter-JumpTable(A1)
  791. ;
  792. ; 3. Point A0 at the “Move.L *-4,-(sp)”
  793. ;        LEA        4+pGNEFilter-JumpTable(A1),A0
  794. ;
  795. ; 4. Stuff the vector.
  796. ;        Move.L    A0,jGNEFilter
  797. ;     or
  798. ;        Move.W    #NewHandle,D0
  799. ;        _SetTrapAddress newOS    <- newOS or newTool, as appropriate.
  800.  
  801. ; Define a macro which does what we just described, but hides the grungy detail.
  802. ;    &trapNumber can be either a trap number or a vector address
  803. ;    &trapType can be newOS, newTool, or Vector
  804. ;    &patch is the label on your patch routine
  805. ;    &jumpTableEntry is the label on your jump table entry
  806.  
  807.     MACRO
  808.     StuffNewAddress &trapNumber, &trapType, &patch, &jumpTableEntry
  809.         LEA        &patch-HeapBlock(A2),A0
  810.         Move.L    A0,&jumpTableEntry-JumpTable(A1)
  811.         LEA        4+&jumpTableEntry-JumpTable(A1),A0
  812.         IF &trapType = 'newOS' THEN
  813.             Move.W    #&trapNumber,D0
  814.             _SetTrapAddress &trapType
  815.         ELSEIF &trapType = 'newTool' THEN
  816.             Move.W    #&trapNumber,D0
  817.             _SetTrapAddress &trapType
  818.         ELSEIF &trapType = 'Vector' THEN
  819.             Move.L    A0,&trapNumber
  820.         ENDIF
  821.     ENDM
  822.  
  823. ;Vectors
  824.     ; to get some time, patch us into jGNEFilter and MenuHook
  825.         StuffNewAddress    jGNEFilter,    Vector,    PatchGNEFilter,    pGNEFilter    ; somebody’s got to get the utility check!
  826.         StuffNewAddress    MenuHook,    Vector,    PatchMenuHook,    pMenuHook
  827.  
  828. ;Traps
  829.     ; patch MenuSelect to give us a chance to stuff MenuHook around tracking in the menubar and menus
  830.         StuffNewAddress    MenuSelect,        newTool,PatchMenuSelect,    pMenuSelect
  831.     ; patch these to count them as they are called.
  832.         StuffNewAddress    NewHandle,        newOS,    PatchNewHandle,        pNewHandle
  833.         StuffNewAddress    DisposeHandle,    newOS,    PatchDisposeHandle, pDisposeHandle
  834.         StuffNewAddress    NewPtr,            newOS,    PatchNewPtr,        pNewPtr
  835.         StuffNewAddress    DisposePtr,        newOS,    PatchDisposePtr,    pDisposePtr
  836.         StuffNewAddress    Read,             newOS,    PatchRead,            pRead
  837.         StuffNewAddress    Write,            newOS,    PatchWrite,            pWrite
  838.         StuffNewAddress    LoadSeg,        newTool,PatchLoadSeg,        pLoadSeg
  839.         StuffNewAddress    GetResource,    newTool,PatchGetResource,    pGetResource
  840.  
  841. RegisterGestaltHandler
  842.         LEA        ReturnTheGestaltHandlerProc-HeapBlock(A2),A0
  843.         Move.L    A0,pGestaltFunc-JumpTable(A1)
  844.         Move.L    #'Sntl',D0
  845.         LEA        4+pGestaltFunc-JumpTable(A1),A0
  846.         _NewGestalt                                ;    If it fails, then something bad happened...
  847.                                                 ;    but nothing we can do about it now
  848. ; JumpTable in A1
  849. ; HeapBlock in A2
  850.  
  851. ; Fix up the bitmap base address in the patch block.
  852.         LEA        pBitMapBaseAddress-HeapBlock(A2),A0
  853.         Move.L    A0,pBitMap-HeapBlock(A2)
  854.  
  855. ;Remember where the jump table entry is so that the patch on MenuSelect can load
  856. ;MenuHook with the jump table entry even though it’s in a separate block
  857.         LEA        4+pMenuHook-JumpTable(A1),A0
  858.         Move.L    A0,pMenuHookEA-HeapBlock(A2)
  859.  
  860.  
  861.         Bra.S    loaded
  862.         
  863. ;Common exit-point.
  864. BailOut
  865.  
  866. ShowStartupIcon
  867.  
  868. ;        PROCEDURE ShowINIT(iconID: Integer; moveX: Integer);
  869.         IMPORT    SHOWINIT:CODE        
  870.  
  871. didntLoadIconID        equ    -4063        
  872. patchLoadedIconID    equ    -4064        
  873.  
  874.         Move.W    #didntLoadIconID,-(a7)            ; Shift held -- Didn’t load
  875.         Bra.S    ShowIt
  876.         
  877. loaded    Move.W    #patchLoadedIconID,-(a7)    ; OK Show the ICON and go
  878. ShowIt    Move.W    #-1,-(a7)
  879.         BSR        SHOWINIT
  880.  
  881. exit    RTS
  882.  
  883. ; What happens to this locked block, you ask?  Easy, the heap is about to
  884. ; get blown away, so we really don’t have to do anything to tidy up.
  885.  
  886.         END
  887.  
  888.  
  889. ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  890.